import Vue from 'vue'
import * as Cesium from 'cesium'
import * as turf from '@turf/turf'

/*
  使用说明：
  1. 使用 Cesium 地图绘制图形时在初始化时 需要配置 terrainProvider
     否则无效  并且地图的canvas 图层在绘制时不能被其他元素遮挡，否则不生效
     var viewer = new Cesium.Viewer('cesiumContainer', {
       terrainProvider: Cesium.createWorldTerrain(),
     }
  2. 初始化地图后 需要在 $nextTick 中再初始化 绘制图形实例
     例： viewer 为初始化地图后返回的实例
      const drawGeometry = new DrawGeometry(viewer)
      this.drawGeometry = drawGeometry
  3. 点击绘制按钮后调用 draw(options={}) 函数 ，下方options 有介绍配置项
     例：
      this.drawGeometry.draw({
        success: res => {
          console.log('绘制信息为：', res)
        }
      })
  4. 若不需要再进行绘制了需要调用clear() 函数清除绑定在map上的各种绘制图形事件
     例：
      this.drawGeometry.clear()
 */

function DrawGeometry (viewer) {
  let activeShapePoints = [] //  绘制的点的坐标
  let activeShape // 绘制的点的图形
  let floatingPoint // 动态点图形（当前鼠标点）
  let ellipsoid = viewer.scene.globe.ellipsoid // 笛卡尔坐标系中由等式定义的二次曲面 （x/a）^ 2 +（y/b）^ 2 +（z/c）^ 2 = 1 。主要用于用cesium表示行星体的形状。与其直接构造此对象，不如提供通常使用常量。
  let entities = [] //
  // 初始化 cesium 时间处理器
  let handler = new Vue.prototype.Cesium.ScreenSpaceEventHandler(viewer.canvas)

  // 双击鼠标左键清除默认事件
  viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK)

  // 绘画函数
  const draw = (options = {}) => {
    /*
      options ： 绘画的配置
      1: mode  绘画的模式 默认为line
      2: color  绘制的样式的颜色  默认为红
      3: width 绘制线条的宽度  默认为 4px
      4: success 绘制成功后的回调函数  通过该函数获取 绘制的点的路径 与中心坐标
      5: borderStyle 绘制的图形的样式  solid：实线  dashed ：虚线
    */
    const { mode: drawingMode = 'polygon', color: drawingColor = '#41D4F3', width: lineWidth = 4, success = () => {}, borderStyle = 'dashed' } = options

    // 绘制点事件
    function createPoint (worldPosition) {
      let point = viewer.entities.add({
        position: worldPosition,
        point: {
          color: Cesium.Color.fromCssColorString(drawingColor),
          pixelSize: lineWidth,
          heightReference: Cesium.HeightReference.CLAMP_TO_GROUND
        }
      })
      entities.push(point)
      return point
    }

    // 绘制图形事件
    function drawShape (positionData) {
      let shape
      if (drawingMode === 'line') {
        let linePolylineMaterial
        if (borderStyle === 'solid') {
          linePolylineMaterial = Cesium.Color.fromCssColorString(drawingColor)
        } else if (borderStyle === 'dashed') {
          linePolylineMaterial = new Cesium.PolylineDashMaterialProperty({
            color: Cesium.Color.fromCssColorString(drawingColor)
          })
        }
        shape = viewer.entities.add({
          polyline: {
            positions: positionData,
            clampToGround: true,
            width: lineWidth,
            // material: Cesium.Color.fromCssColorString(drawingColor)
            material: linePolylineMaterial
          }
        })
      } else if (drawingMode === 'polygon') {
        shape = viewer.entities.add({
          polygon: {
            hierarchy: positionData,
            material: new Cesium.ColorMaterialProperty(Cesium.Color.fromCssColorString(drawingColor).withAlpha(0.5))
          }
        })
      } else if (drawingMode === 'circle') {
        // 当positionData为数组时绘制最终图，如果为function则绘制动态图
        let value = typeof positionData.getValue === 'function' ? positionData.getValue(0) : positionData
        // var start = activeShapePoints[0];
        // var end = activeShapePoints[activeShapePoints.length - 1];
        // var r = Math.sqrt(Math.pow(start.x - end.x, 2) + Math.pow(start.y - end.y, 2));
        // r = r ? r : r + 1;
        shape = viewer.entities.add({
          position: activeShapePoints[0],
          name: 'Blue translucent, rotated, and extruded ellipse with outline',
          type: 'Selection tool',
          ellipse: {
            semiMinorAxis: new Cesium.CallbackProperty(function () {
              // 半径 两点间距离
              let r = Math.sqrt(Math.pow(value[0].x - value[value.length - 1].x, 2) + Math.pow(value[0].y - value[value.length - 1].y, 2))
              return r ? r : r + 1
            }, false),
            semiMajorAxis: new Cesium.CallbackProperty(function () {
              let r = Math.sqrt(Math.pow(value[0].x - value[value.length - 1].x, 2) + Math.pow(value[0].y - value[value.length - 1].y, 2))
              return r ? r : r + 1
            }, false),
            material: Cesium.Color.fromCssColorString(drawingColor).withAlpha(0.5),
            outline: true
          }
        })
      } else if (drawingMode === 'rectangle') {
        // 当positionData为数组时绘制最终图，如果为function则绘制动态图
        let arr = typeof positionData.getValue === 'function' ? positionData.getValue(0) : positionData
        shape = viewer.entities.add({
          name: 'Blue translucent, rotated, and extruded ellipse with outline',
          rectangle: {
            coordinates: new Cesium.CallbackProperty(function () {
              let obj = Cesium.Rectangle.fromCartesianArray(arr)
              // if(obj.west==obj.east){ obj.east+=0.000001};
              // if(obj.south==obj.north){obj.north+=0.000001};
              return obj
            }, false),
            material: Cesium.Color.fromCssColorString(drawingColor).withAlpha(0.5)
          }
        })
      }
      return shape
    }

    // 在cesium 地图中给 鼠标左键 绑定事件
    handler.setInputAction(function (event) {
      // We use `viewer.scene.pickPosition` here instead of `viewer.camera.pickEllipsoid` so that
      // we get the correct point when mousing over terrain.
      // scene.pickPosition只有在开启地形深度检测，且不使用默认地形时是准确的。
      let earthPosition = viewer.scene.pickPosition(event.position)
      // `earthPosition` will be undefined if our mouse is not over the globe.
      if (Cesium.defined(earthPosition)) {
        if (activeShapePoints.length === 0) {
          floatingPoint = createPoint(earthPosition)
          activeShapePoints.push(earthPosition)
          let dynamicPositions = new Cesium.CallbackProperty(function () {
            if (drawingMode === 'polygon') {
              return new Cesium.PolygonHierarchy(activeShapePoints)
            }
            return activeShapePoints
          }, false)
          activeShape = drawShape(dynamicPositions) // 绘制动态图
          entities.push(activeShape)
        }
        activeShapePoints.push(earthPosition)
        createPoint(earthPosition)
      }
      // htmic
      // 将笛卡尔坐标转换为地理坐标
      let cartographic = ellipsoid.cartesianToCartographic(earthPosition)
      // 将弧度转为度的十进制度表示 经纬度
      let longitude = Cesium.Math.toDegrees(cartographic.longitude)
      let latitude = Cesium.Math.toDegrees(cartographic.latitude)
    }, Cesium.ScreenSpaceEventType.LEFT_CLICK)

    // 在cesium 地图中给 鼠标移动 绑定事件
    handler.setInputAction(function (event) {
      if (Cesium.defined(floatingPoint)) {
        let newPosition = viewer.scene.pickPosition(event.endPosition)
        if (Cesium.defined(newPosition)) {
          floatingPoint.position.setValue(newPosition)
          activeShapePoints.pop()
          activeShapePoints.push(newPosition)
        }
      }
    }, Cesium.ScreenSpaceEventType.MOUSE_MOVE)

    // Redraw the shape so it's not dynamic and remove the dynamic shape.
    // 结束绘制地图事件
    function terminateShape () {
      activeShapePoints.pop() // 去除最后一个动态点
      if (activeShapePoints.length) {
        entities.push(drawShape(activeShapePoints)) // 绘制最终图
      }
      viewer.entities.remove(floatingPoint) // 去除动态点图形（当前鼠标点）
      viewer.entities.remove(activeShape) // 去除动态图形

      let polyCenter = Cesium.BoundingSphere.fromPoints(activeShapePoints).center

      polyCenter = Cesium.Ellipsoid.WGS84.scaleToGeodeticSurface(polyCenter)
      let res = activeShapePoints.map(point => convertWGS84(point))
      let activeShapePointsList = activeShapePoints.map(item => {
        const cartographic = cartesianToCartographic(viewer, item)
        return cartographic
      })
      activeShapePointsList.push(activeShapePointsList[0])
      const turfPolygon = turf.polygon([activeShapePointsList])
      const turfCentroid = turf.centroid(turfPolygon)
      const centerP = turfCentroid.geometry.coordinates

      if (options && options.success) {
        options.success({
          paths: res,
          // centerPoint: convertWGS84(polyCenter)
          centerPoint: {
            x: centerP[0],
            y: centerP[1]
          }
        })
      }
      floatingPoint = undefined
      activeShape = undefined
      activeShapePoints = []
    }

    // 转换成 WGS84 坐标系
    function convertWGS84 (newPosition) {
      // 将笛卡尔坐标转换为地理坐标
      let cartographic = ellipsoid.cartesianToCartographic(newPosition)
      // 将弧度转为度的十进制度表示 经纬度
      let longitude = Cesium.Math.toDegrees(cartographic.longitude)
      let latitude = Cesium.Math.toDegrees(cartographic.latitude)
      return {
        x: longitude,
        y: latitude,
        z: newPosition.z
      }
    }

    handler.setInputAction(function (event) {
      terminateShape()
    }, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
  }

  // 清除 绘制中用到的鼠标事件
  function clear () {
    viewer.scene.globe.depthTestAgainstTerrain = false
    handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK) // 移除事件
    handler.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK) // 移除事件
    handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK) // 移除事件
    handler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE) // 移除事件
  }

  function removeEntity () {
    entities &&
      entities.forEach(item => {
        viewer.entities.remove(item)
      })
  }

  // 世界坐标转换为经纬度
  function cartesianToCartographic (viewer, p) {
    let ellipsoid = viewer.scene.globe.ellipsoid
    let cartesian3 = new Cesium.Cartesian3(p.x, p.y, p.z)
    let cartographic = ellipsoid.cartesianToCartographic(cartesian3)
    let lat = Cesium.Math.toDegrees(cartographic.latitude)
    let lng = Cesium.Math.toDegrees(cartographic.longitude)
    let alt = cartographic.height
    return [lng, lat]
  }

  return {
    draw,
    clear,
    removeEntity
  }
}

export default DrawGeometry
